#pragma once

#include <vector>
#include <iostream>
#include <string>
#include <assert.h>
// 网络库底层的缓冲区定义
class Buffer 
{
public:
  static const size_t kCheapPrepend = 8;
  static const size_t kInitialSize = 1024;

  explicit Buffer(size_t initialSize = kInitialSize)
    : m_buffer(kCheapPrepend + kInitialSize)
    , m_readIndex(kCheapPrepend)
    , m_writeIndex(kCheapPrepend)
  {}

  size_t readableBytes() const {
    return m_writeIndex - m_readIndex;
  }

  size_t writeableBytes() const {
    return m_buffer.size() - m_writeIndex;
  }

  size_t prependableBytes() const {
    return m_readIndex;
  }

  const char* peek() const { // 返回可读数据缓冲区的起始地址
    return begin() + m_readIndex;
  }
  void retrieve(size_t len) { // 将可读数据缓冲区前移
    if (len < readableBytes()) {
      m_readIndex += len;      
    } else {
      retrieveAll();
    }   
  }

  void retrieveAll() {
    m_readIndex = kCheapPrepend;
    m_writeIndex = kCheapPrepend;
  }
  std::string retrieveAllToString() {
    return retrieveToString(readableBytes());
  }

  std::string retrieveToString(size_t len) {
    assert(len <= readableBytes());
    std::string result(peek(), len);
    retrieve(len);
    return result;
  }
  void ensureWriteableBytes(size_t len) {
    if (writeableBytes() < len) {
      makeSpace(len);
    }
  }

  void makeSpace(size_t len) {
    if (writeableBytes() + prependableBytes() < len + kCheapPrepend) {
      m_buffer.resize(m_writeIndex + len);
    } else {
      assert(kCheapPrepend < m_readIndex);
      size_t readable = readableBytes();
      std::copy(begin() + m_readIndex, begin() + m_writeIndex, begin() + kCheapPrepend);
      m_readIndex = kCheapPrepend;
      m_writeIndex = m_readIndex + readable;
      assert(readable == readableBytes());
    }
  }

  void append(const char *data, size_t len) {
    ensureWriteableBytes(len);
    std::copy(data, data + len, beginWrite());
  }

  char* beginWrite() {
    return begin() + m_writeIndex;
  }
  const char* beginWrite() const {
    return begin() + m_writeIndex;
  }
  ssize_t readFd(int fd, int* savedErrno);
  ssize_t writeFd(int fd, int* savedErrno);
private:
  char* begin() {
    return &*m_buffer.begin();
  }
  const char* begin() const {
    return &*m_buffer.begin();
  }

private:
  std::vector<char> m_buffer;
  size_t m_readIndex;
  size_t m_writeIndex;  
};